home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 08 - 1992 / 08.06 Oct 92 / Screen Picker / ShowIconFamily Library / ShowIconFamily.c next >
Encoding:
C/C++ Source or Header  |  1991-08-25  |  9.2 KB  |  357 lines  |  [TEXT/KAHL]

  1. /*
  2.     ShowIconFamily.c
  3.     
  4.     ShowINIT compatible routine that shows 'ICN#' and 'iclx' flavor icons.
  5.     For use by all INITs in System 7 and beyond.
  6.     
  7.     by Patrick C. Beard.
  8.     modified by James W. Walker for compatibility with IconWrap 1.2,
  9.     and for use as a separate code resource.
  10.     
  11.     Instructions for use:
  12.     
  13.         • Create a family of icons with ResEdit 2.1 or later.  This will
  14.             include 'ICN#', 'icl4', & 'icl8' icons.
  15.         
  16.         To use within a larger INIT project:
  17.             • #define SEPARATE_CODE 0  below.
  18.             • Use SetUpA4 to set up Think C globals.
  19.             • Call ShowIconFamily() with the resource id of the family
  20.                 that you used.
  21.         
  22.         To use as a separate code resource:
  23.             • #define SEPARATE_CODE 1  below.
  24.             • Set the project type to code resource, set the code type
  25.                 and resource ID (I use type 'Code', ID -4048 for cdevs),
  26.                 compile and merge into your INIT or cdev file.
  27.             • In your main INIT code, call ShowIconFamily like so:
  28.                 show_init = GetResource( 'Code', -4048 );
  29.                 HLock( show_init );
  30.                 CallPascal( icon_family_ID, *show_init );
  31.                 HUnlock( show_init );
  32.  
  33.     Enhancements:
  34.         
  35.         • Uses 'iclx' & 'ICN#' icons from the Finder's "icon family" in System 7.
  36.         • Generates a position for icons that is guaranteed to be on screen, while
  37.           remaining compatible with previous releases of ShowInit.
  38.     
  39.     This code is completely public domain.  Let's hope this becomes a new standard.
  40.     
  41.     This code is derived from the original ShowInit by Paul Mercer, Darin Adler,
  42.     Paul Snively, and Steve Capps.
  43.     
  44.     Special thanks to Ben Haller & Rob Vaterlaus for valuable suggestions and help.
  45.  */
  46.  
  47. #define SEPARATE_CODE    0
  48.  
  49. #include <OSUtils.h>
  50. #include <QuickDraw.h>
  51.  
  52. #if SEPARATE_CODE
  53. #include <SetUpA4.h>    /* JWW */
  54. #endif
  55.  
  56. #ifndef nil
  57. #define nil ((void*)0L)
  58. #endif
  59. #ifndef topLeft
  60. #define topLeft(r) ((Point*)&r)[0])
  61. #endif
  62. #ifndef botRight
  63. #define botRight(r) ((Point*)&r)[1])
  64. #endif
  65.  
  66. typedef struct QDGlobals {
  67.     char privates[76];
  68.     long randSeed;
  69.     BitMap screenBits;
  70.     Cursor arrow;
  71.     Pattern dkGray;
  72.     Pattern ltGray;
  73.     Pattern gray;
  74.     Pattern black;
  75.     Pattern white;
  76.     GrafPtr thePort;
  77.     long    end;
  78. } QDGlobals;
  79.  
  80. static short theDepth;                /* the depth the monitor is in. */
  81. static CGrafPtr port;
  82.  
  83. static void DrawBWIcon(short iconId);
  84. static void DrawColorIcon(short iconId);
  85. static void Next_position( void );
  86.  
  87. /* this is where it all happens. */
  88.  
  89. #if SEPARATE_CODE
  90. void main(short iconId)
  91. #else
  92. void ShowIconFamily(short iconId)
  93. #endif
  94. {
  95.     long oldA5;
  96.     QDGlobals qd;                /* our QD globals. */
  97.     SysEnvRec environment;        /* machine configuration. */
  98.     CGrafPort gp;                /* our grafport. */
  99.     
  100. #if SEPARATE_CODE
  101.     RememberA0(); /* JWW */
  102.     SetUpA4(); /* JWW */
  103. #endif
  104.     
  105.     /* get a value for A5, a structure that mirrors qd globals. */
  106.     oldA5 = SetA5((long)&qd.end);
  107.     InitGraf(&qd.thePort);
  108.     
  109.     /* find out what kind of machine this is. */
  110.     SysEnvirons(curSysEnvVers, &environment);
  111.     if (environment.hasColorQD) {
  112.         theDepth = (**(**GetMainDevice()).gdPMap).pixelSize;
  113.         if (theDepth < 4)
  114.             theDepth = 1;
  115.     } else {
  116.         theDepth = 1;
  117.     }
  118.  
  119.     /* see what type of port to open. */
  120.     if (theDepth >= 4) {
  121.         OpenCPort(&gp);
  122.     } else {
  123.         OpenPort((GrafPtr)&gp);
  124.     }
  125.     port = &gp;
  126.     
  127.     if (theDepth == 1)
  128.         DrawBWIcon(iconId);
  129.     else
  130.         DrawColorIcon(iconId);
  131.     
  132.     Next_position(); /* JWW */
  133.  
  134.     SetA5(oldA5);
  135. #if SEPARATE_CODE
  136.     RestoreA4();
  137. #endif
  138. }
  139.  
  140. /*
  141.     ShowInit's information is nestled at the tail end of CurApName.
  142.     It consists of a short which encodes the next horizontal offset,
  143.     and another short which is that value checksummed with the function below.
  144.  */
  145.  
  146. #define CurApName_LM    0x910
  147. #define ShowINITTable ((short*)(CurApName_LM + 32 - 4))
  148. #define CheckSumConst 0x1021        /* magic value to check-sum with. */
  149.  
  150. #define InitialXPosition 8            /* initial horizontal offset. */
  151. #define YOffset            40            /* constant from bottom to place the icon. */
  152. #define XOffset            40            /* amount to change it by. */
  153.  
  154. /* CheckSum() computes the magic value to determine if ShowInit's have run already. */
  155.  
  156. static short CheckSum(register short x)
  157. {
  158.     asm {
  159.         rol.w    #1, x
  160.     }
  161.     return (x ^ CheckSumConst);
  162. }
  163.  
  164. /*
  165.     GetIconRect() generates an appropriate rectangle to display the
  166.     next INIT's icon in.
  167.     It is also responsible for updating the horizontal
  168.     position in low memory.  This is a departure from
  169.     the original ShowInit code, which updates low
  170.     memory AFTER displaying the icon. -- changed by JWW
  171.     This code won't generate an icon position until it is certain that the icon can be loaded, so the
  172.     same behaviour occurs.
  173.     
  174.     This routine also generates a rectangle which is guaranteed to be onscreen.  It
  175.     does this by taking the horizontal offset modulo the screen width to generate
  176.     the horizontal position of the icon, and the offset divided by the screen
  177.     width to generate the proper row.
  178.  */
  179.  
  180. void GetIconRect(register Rect* iconRect)
  181. {
  182.     register short screenWidth = port->portRect.right - port->portRect.left;
  183.     /* if we are the first INIT to run we need to initialize the horizontal value. */
  184.     if (CheckSum(ShowINITTable[0]) != ShowINITTable[1])
  185.         ShowINITTable[0] = InitialXPosition;
  186.     
  187.     /* compute top left of icon's rect. */
  188.     iconRect->left = (ShowINITTable[0] % screenWidth);
  189.     iconRect->top = port->portRect.bottom - YOffset * (1 + (ShowINITTable[0] / screenWidth));
  190.     iconRect->right = iconRect->left + 32;
  191.     iconRect->bottom = iconRect->top + 32;
  192.     
  193. }
  194.  
  195. /*
  196.     JWW: In Beard's original version, this was done at the end of
  197.     GetIconRect. That caused incorrect behavior when IconWrap 1.2 was
  198.     used to wrap icons.  Namely, if an INIT using that version of
  199.     ShowIconFamily was the first in a row, then the second icon in that
  200.     row would land on top of it.
  201. */
  202. static void Next_position( void )
  203. {
  204.     /* advance the position for the next icon. */
  205.     ShowINITTable[0] += XOffset;
  206.     
  207.     /* recompute the checksum. */
  208.     ShowINITTable[1] = CheckSum(ShowINITTable[0]);    
  209. }
  210.  
  211. /* DrawBWIcon() draws the 'ICN#' member of the icon family. */
  212.  
  213. void DrawBWIcon(short iconId)
  214. {
  215.     Handle icon;
  216.     Rect iconRect;
  217.     BitMap source, destination;
  218.     
  219.     icon = Get1Resource('ICN#', iconId);
  220.     if (!icon)
  221.         return;
  222.     HLock(icon);
  223.     
  224.     GetIconRect(&iconRect);
  225.  
  226.     /* prepare the source and destination bitmaps. */
  227.     source.baseAddr = *icon + 128;                    /* mask address. */
  228.     source.rowBytes = 4;
  229.     SetRect(&source.bounds, 0, 0, 32, 32);
  230.     destination = ((GrafPtr)port)->portBits;
  231.     
  232.     /* transfer the mask. */
  233.     CopyBits(&source, &destination, &source.bounds, &iconRect, srcBic, nil);
  234.     
  235.     /* and the icon. */
  236.     source.baseAddr = *icon;    
  237.     CopyBits(&source, &destination, &source.bounds, &iconRect, srcOr, nil);
  238.     
  239.     ReleaseResource(icon);
  240. }
  241.  
  242. /*
  243.     ChooseIcon() chooses the optimal icon for the current screen depth.
  244.     
  245.     Priorities for choosing icons:
  246.         1. match the bit depth to the icon.
  247.         2. use alternate bit depth version if available.
  248.         3. draw the black & white version.
  249.  */
  250.     
  251. Handle ChooseIcon(short iconId, short* suggestedDepth)
  252. {
  253.     short depth = *suggestedDepth;
  254.     Handle icon = nil;
  255.  
  256.     if (depth == 4) {
  257.         icon = Get1Resource('icl4', iconId);
  258.         if (!icon) {
  259.             /* try alternate depth. */
  260.             icon = Get1Resource('icl8', iconId);
  261.             if (icon)
  262.                 depth = 8;
  263.         }
  264.     } else {
  265.         depth = 8;
  266.         icon = Get1Resource('icl8', iconId);
  267.         if (!icon) {
  268.             /* try alternate depth. */
  269.             icon = Get1Resource('icl4', iconId);
  270.             if (icon)
  271.                 depth = 4;
  272.         }
  273.     }
  274.     
  275.     *suggestedDepth = depth;
  276.     return icon;
  277. }
  278.  
  279. /* DrawColorIcon() draws the appropriate icon for the current screen depth. */
  280.  
  281. void DrawColorIcon(short iconId)
  282. {
  283.     short depthToUse;
  284.     Handle mask, icon;
  285.     CTabHandle clut;
  286.     PixMapHandle source;
  287.     BitMap maskBits;
  288.     long rowBytes;
  289.     Rect iconRect, bounds;
  290.     
  291.     /* by default we will be using the actual depth of the screen. */
  292.     depthToUse = theDepth;
  293.     icon = ChooseIcon(iconId, &depthToUse);
  294.     
  295.     /* if no color icon available, draw the black & white icon. */
  296.     if (!icon) {
  297.         DrawBWIcon(iconId);
  298.         return;
  299.     }
  300.     HLock(icon);
  301.     
  302.     /* get the black & white icon to get the mask drawn. */
  303.     mask = Get1Resource('ICN#', iconId);
  304.     if (!mask)
  305.         return;
  306.     HLock(mask);
  307.  
  308.     /* get the correct color lookup table. */
  309.     clut = GetCTable(depthToUse);
  310.     if (!clut)
  311.         return;
  312.     
  313.     /* create a pixmap to stick the icon bits into for screen blitting. */
  314.     source = NewPixMap();
  315.     if (!source) {
  316.         DisposCTable(clut);
  317.         return;
  318.     }
  319.     
  320.     /* set up the source pixmap with the appropriate bounds, depth, and clut. */
  321.     bounds.top = bounds.left = 0;
  322.     bounds.bottom = bounds.right = 32;
  323.     rowBytes = (((depthToUse * 32) + 15) / 16) * 2;
  324.     (**source).baseAddr = *icon;
  325.     (**source).rowBytes = ((short)rowBytes) | 0x8000;
  326.     (**source).bounds = bounds;
  327.     (**source).pixelType = 0;            /* chunky model. */
  328.     (**source).pixelSize = depthToUse;
  329.     (**source).cmpCount = 1;            /* if in 32 bit mode this will be 3, so must change. */
  330.     (**source).cmpSize = depthToUse;    /* only chunky images used. */
  331.     DisposCTable((**source).pmTable);    /* dispose of default, uninitialized table. */
  332.     (**source).pmTable = clut;
  333.  
  334.     /* get position to draw icon in. */
  335.     GetIconRect(&iconRect);
  336.  
  337.     /* prepare the mask bitmap. */
  338.     maskBits.baseAddr = *mask + 128;                    /* mask address. */
  339.     maskBits.rowBytes = 4;
  340.     maskBits.bounds = bounds;
  341.  
  342.     /* punch out the mask. */    
  343.     CopyBits(&maskBits, &port->portPixMap, &bounds, &iconRect, srcBic, nil);
  344.     
  345.     /* draw the actual color icon. */
  346.     HLock((Handle)source);
  347.     CopyBits(*source, &port->portPixMap, &bounds, &iconRect, srcOr, nil);
  348.     
  349.     /* release everything we've allocated. */
  350.     (**source).baseAddr = nil;
  351.     DisposPixMap(source);
  352.     
  353.     /* release the icon and mask. */
  354.     ReleaseResource(icon);
  355.     ReleaseResource(mask);
  356. }
  357.